/*
  (c) The Grid Team 2014
  All rights reserved.
  Work may not be reproduced in any way without the makers' permission

  raspberry.ino (Post NY Code)
  View changes on GitHub and code.google.com
*/

#include <SoftwareSerial.h>

#include "grid_common.h"
#include "serial_communication.h"

unsigned long lastForwardTime;
int colour_id = 0;

int gameVars[MAX_VALUES]; //Inputs for the game modes from processMessages()

 //Move this??
int gameMode = 1; //Default as Interactive

long prevState = -1; //??

int numOfGameModes = 12;
String GAME_MODE_NAMES[] = {
  "NOTHING", "INTERACTIVE", "SHOW", "FLOW", "CLEAR", "X", /*6*/ "TEST COMMUNICATION",
  "CHRISTMAS","matthewsFlashingFrenzy","SPIN","mysteriousGrowth", /*11*/"Flow2"};

void resetCommonState() { //Clear gameVars and lastMessage
  for (int i = 0; i < MAX_VALUES; i++) {
    gameVars[i] = 0;
    //lastMessage[i] = 0;
  }
  //lastMessageLen = 0;
}

void setup(){
  
  //Serial.println("Welcome to the Grid! Start Up Successful!");
  initCommon();
  initCommunication();

  pinMode(13,OUTPUT);
  
  randomSeed(analogRead(0));

  resetCommonState();
  gameMode = 1;
  
  gameVars[0] = 1;
  gameVars[1] = 2;
  gameVars[2] = 5;

}

boolean newState = false;

boolean getNewState() {
  return newState;
}

void setNewState(boolean newValue) {
  newState = newValue;
}

void loop(){
  newState = false;

  processMessages();

  if (gameMode < 0 || gameMode >= numOfGameModes) {
    // not supported game mode
    return;
  }

  if (newState) {
    Serial.println("In game mode: " + GAME_MODE_NAMES[gameMode]);
  }

  switch(gameMode){     
    case 0: // NOTHING
      doNothing();
      break;
    case 1: // INTERACTIVE
      interactive(numberToColor(gameVars[0]),numberToColor(gameVars[1]), gameVars[2]);
      break;
    case 2: // SHOW
      playShow(numberToColor(gameVars[0]),gameVars[1], gameVars[2]);
      break;
    case 3: // FLOW
      if(newState){
        prevState = -1;
        initFlow();
      }
      flow();
      break;
    case 4: // CLEAR
      clearAll();
      pushPixels();
      break;
    case 5: // X
      break;
    case 6: // TEST COMMUNICATION
      communicationTest();
      break;
    case 7:
      christmas(numberToColor(gameVars[0]),gameVars[1]);
      break;
    case 8:
      matthewsFlashingFrenzy(numberToColor(gameVars[0]),gameVars[1]);
      break;
    case 9: // SPIN
      spin(gameVars[0]);
      break;
    case 10:
      mysteriousGrowth(numberToColor(gameVars[0]),gameVars[1]);
      break;
    case 11: // Flow2
      if(newState) {
        prevState = -1;
        initFlow();
      }
      flow2();
      break;
  }
  //delay(5);
}

void setCoords(int* values, int num) {
  switch (num) {
    case 1:
      setX(0); setY(0); setOriginX(0); setOriginY(0);
      break;
    case 3:
      setX(values[1]); setY(values[2]); setOriginX(values[1]); setOriginY(values[2]);
      break;
    case 5:
      setX(values[1]); setY(values[2]); setOriginX(values[3]); setOriginY(values[4]);
      break;
  }
  int topSend[] = {6, getX(), getY() + 1, getOriginX(), getOriginY()};
  portWrite(3, topSend, 5);
  int rightSend[] = {6,getX()+1, getY(), getOriginX(), getOriginY()};
  portWrite(4, rightSend, 5);
}

void processMessages() {//Mega method that processes incoming message according to their message type
  int values[MAX_VALUES]; // holds message from neighboring tile in format: [type, int, int, ...]

  for(int i =0; i<MAX_VALUES; i++){
    values[i] = 0; //Clears MAX VALUES
  }
  int num; //numbers of integers stored in the message including type
  //Serial.println("LOOKING");
  for (int i = 0; i < NUMBER_OF_PORTS; i++) {
    num = portRead(i, values, MAX_VALUES);
    if (num == 0) {
      continue;
    }
    printMessage(i, values, num);

    if (values[0] == STATE_MSG_TYPE  && num == 3) {
      if(getState(i) != values[1]){ //Set up FLOW stuff
        setChanged(true);
        setState(i, values[1]);
      }
      setColor(i, numberToColor(values[2]));
      if (gameMode == 6) { // TEST COMMUNICATION MODE
        flashLight(i, CYAN);
      }
    }
    
    // For now, we are not expecting messages from TOP and RIGHT neighbors.
    if ( i == 3 || i == 4) {
      continue;
    }
    
    // Setting new game mode
    if(values[0] == SET_GAME_MODE_MSG_TYPE && num >= 2){
      newState = true;
      gameMode = values[1];
      for(int i = 2; i< num; i++){
        gameVars[i-2] = values[i];
        //Serial.println(gameVars[i-2]); 
      }
      broadcastForward(values, num);
    }

    switch (values[0]) {
      case SET_COORD_MSG_TYPE: //6
        setCoords(values,num);
        break;
      case SET_FLOW_POSITIONS: // 8
        broadcastForward(values,num);
        setFlowPositions(values,num);
        break;
      case STATE_EXPIRATION_MSG_TYPE: // 11
        clearFlow2State(i);
        break;
      case CHOOSE_PRESET_FLOW_GAME_MSG_TYPE: //12
        if (num >= 2) {
          broadcastForward(values, num);
          choosePresetFlowGame(values[1]);
        }
        break;
      case SET_PRESET_FLOW_GAME_MSG_TYPE: //13
        forward(values, num);
        setPresetFlowGame(values+1, num-1);
        break;
      case APPEND_PRESET_FLOW_GAME_MSG_TYPE: //14
        forward(values, num);
        appendPresetFlowGame(values+1, num-1);
        break;
      case FLOW_ANIMATION_MSG_TYPE: //16
        forward(values, num);
        int step = num>1 ? values[1] : -1;
        nextAnimation(step);
        break;
    }
  }
}

